#pragma once

//using row vector... i.e matrix will be
// x y z 0
// x y z 0
// x y z 0
// t t t 1
//
class Matrix4d
{
public:
	Matrix4d() : _invalid(false) 
	{
		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				_m[i][j] = 0;
			}
		}
	}
	
	Matrix4d(double n) : _invalid(false)
	{
		for (unsigned int i = 0; i < 4; ++i)
		{
			for (unsigned int j = 0; j < 4; ++j)
			{
				_m[i][j] = (i == j) ? n : 0.0;
			}
		}
	}


	Matrix4d(	double a0, double a1, double a2, double a3,
				double b0, double b1, double b2, double b3,
				double c0, double c1, double c2, double c3,
				double d0, double d1, double d2, double d3) : _invalid(false)
	{
		_m[0][0] = a0; _m[0][1] = a1; _m[0][2] = a2; _m[0][3] = a3;
		_m[1][0] = b0; _m[1][1] = b1; _m[0][2] = b2; _m[0][3] = b3;
		_m[2][0] = c0; _m[2][1] = c1; _m[0][2] = c2; _m[0][3] = c3;
		_m[3][0] = d0; _m[3][1] = d1; _m[0][2] = d2; _m[0][3] = d3;
	}

	
	Matrix4d(const Matrix4d& o) : _invalid(false)
	{
		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				_m[i][j] = o._m[i][j];
			}
		}
	}

	Matrix4d& operator=(const Matrix4d& m);
	Matrix4d& Inverse();
	Matrix4d& Transpose();
	Matrix4d GetInverse();
	Matrix4d GetTranspose();

	Matrix4d& Identity();
	Matrix4d& Translate(double x, double y, double z);
	Matrix4d& Scale(double x, double y, double z);
	Matrix4d& RotateX(double n);
	Matrix4d& RotateY(double n);
	Matrix4d& RotateZ(double n);
	Matrix4d& Matrix4d RotateAxis(double n, const Vector3d& v);
	
	const double *operator[](unsigned int i) const { return _m[i]; }
	double *operator[](unsigned int i) const { return _m[i];
	
	Matrix4d& operator *=(const Matrix4d& a);

	friend Matrix4d operator *(const Matrix4d& a, const Matrix4d& b);
	friend Vector3d operator *(const Matrix4d& a, const Vector3d& v);
	friend Matrix4d Inverse(const Matrix4d& a);
	friend Matrix4d Transpose(const Matrix4d& a);

protected:
	double _m[4][4];
	bool _invalid;
};